import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * Process for monitoring a filesystem for changes
 * 
 * @author jjnguy
 * 
 */
public class FileSystemListener implements Runnable {

   private List<ChangeListener> listeners;

   private File rootFile;
   private long lastChecked;
   private long interval;

   public FileSystemListener(String root, long interval) {
      rootFile = new File(root);
      listeners = new ArrayList<ChangeListener>();
      this.interval = interval;
   }

   public void addChangeListener(ChangeListener listener) {
      listeners.add(listener);
   }

   @Override
   public void run() {
      while (true) {
         long now = System.currentTimeMillis();
         List<File> changedFiles = getFilesChangedSince(rootFile, lastChecked);
         if (!changedFiles.isEmpty()) {
            for (ChangeListener listener : listeners) {
               listener.fileSystemChanged(changedFiles);
            }
         }
         lastChecked = now;
         try {
            Thread.sleep(interval);
         } catch (InterruptedException e) {
         }
      }
   }

   /**
    * Recursively checks a filesystem for changes.
    * 
    * @param toCheck
    *           the File or folder to check for changes
    * @param changed
    *           the date to check if a file has changed since
    * @return a list of files that have changed since the given date
    */
   public static List<File> getFilesChangedSince(File toCheck, long changed) {
      List<File> changedFiles = new ArrayList<File>();
      if (toCheck.lastModified() > changed) {
         changedFiles.add(toCheck);
      }
      if (toCheck.isDirectory()) {
         for (File f : toCheck.listFiles()) {
            changedFiles.addAll(getFilesChangedSince(f, changed));
         }
      }
      return changedFiles;
   }

   /**
    * Interface for acting when a file system changed
    * 
    * @author jjnguy
    * 
    */
   public static interface ChangeListener {
      public void fileSystemChanged(List<File> changedFiles);
   }
}
